﻿@page "/settings/general"
@inherits MainBase
@inject LanguageService LanguageService
@using Microsoft.Extensions.Localization
@using AliasVault.Client.Services
@using AliasVault.Client.Services.JsInterop.Models

<LayoutPageTitle>@Localizer["PageTitle"]</LayoutPageTitle>

<PageHeader
    BreadcrumbItems="@BreadcrumbItems"
    Title="@Localizer["PageTitle"]"
    Description="@Localizer["PageDescription"]">
</PageHeader>

<div class="p-4 mb-4 mx-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    <h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">@Localizer["AppLanguageTitle"]</h3>

    <div class="mb-4">
        <label for="appLanguage" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["AppLanguageLabel"]</label>
        <select @bind="AppLanguage" @bind:after="UpdateAppLanguage" id="appLanguage" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            @foreach (var language in LanguageService.GetSupportedLanguages())
            {
                <option value="@language.Key">@LanguageService.GetLanguageFlag(language.Key) @language.Value</option>
            }
        </select>
        <span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
            @Localizer["AppLanguageDescription"]
        </span>
    </div>
</div>

<div class="p-4 mb-4 mx-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    <h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">@Localizer["EmailSettingsTitle"]</h3>

    <div class="mb-4">
        <label for="defaultEmailDomain" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["DefaultEmailDomainLabel"]</label>
        <select @bind="DefaultEmailDomain" @bind:after="UpdateDefaultEmailDomain" id="defaultEmailDomain" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            @if (HasValidPrivateDomains())
            {
                <optgroup label="@Localizer["PrivateDomainsLabel"]">
                    @foreach (var domain in PrivateDomains)
                    {
                        <option value="@domain">@domain</option>
                    }
                </optgroup>
            }
            else {
                <optgroup label="@Localizer["PrivateDomainsLabel"]">
                    <option disabled value="_">@Localizer["PrivateDomainsDisabledLabel"]</option>
                </optgroup>
            }
            <optgroup label="@Localizer["PublicDomainsLabel"]">
                @foreach (var domain in PublicDomains)
                {
                    <option value="@domain">@domain</option>
                }
            </optgroup>
        </select>
        <span class="block text-sm font-normal text-gray-500 dark:text-gray-400 mt-2">
            @Localizer["DefaultEmailDomainDescription"] @Localizer["DefaultEmailDomainDescriptionNote"] <a href="https://docs.aliasvault.net/misc/private-vs-public-email.html" class="text-primary-500 hover:text-primary-700 hover:underline" target="_blank" rel="noopener">@Localizer["DefaultEmailDomainLearnMore"]</a>.
        </span>
    </div>

    <div class="flex items-center mb-4">
        <input @bind="AutoEmailRefresh"  @bind:after="UpdateAutoEmailRefresh" id="autoEmailRefresh" type="checkbox" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
        <label for="autoEmailRefresh" class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">@Localizer["AutoEmailRefreshLabel"]</label>
    </div>
</div>

<div class="p-4  mx-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    <h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">@Localizer["AliasSettingsTitle"]</h3>

    <div class="mb-4">
        <label for="defaultIdentityLanguage" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["AliasGenerationLanguageLabel"]</label>
        <select @bind="DefaultIdentityLanguage" @bind:after="UpdateDefaultIdentityLanguage" id="defaultIdentityLanguage" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            @foreach (var language in AvailableLanguages)
            {
                <option value="@language.Value">@language.Flag @language.Label</option>
            }
        </select>
        <span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
            @Localizer["AliasGenerationLanguageDescription"]
        </span>
    </div>

    <div class="mb-4">
        <label for="defaultIdentityGender" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["AliasGenerationGenderLabel"]</label>
        <select @bind="DefaultIdentityGender" @bind:after="UpdateDefaultIdentityGender" id="defaultIdentityGender" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            <option value="random">@Localizer["RandomOption"]</option>
            <option value="male">@Localizer["MaleOption"]</option>
            <option value="female">@Localizer["FemaleOption"]</option>
        </select>
        <span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
            @Localizer["AliasGenerationGenderDescription"]
        </span>
    </div>

    <div class="mb-4">
        <label for="defaultIdentityAgeRange" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["AliasGenerationAgeRangeLabel"]</label>
        <select @bind="DefaultIdentityAgeRange" @bind:after="UpdateDefaultIdentityAgeRange" id="defaultIdentityAgeRange" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            @foreach (var ageRange in AvailableAgeRanges)
            {
                <option value="@ageRange.Value">
                    @(ageRange.Value == "random" ? Localizer["RandomOption"] : ageRange.Label)
                </option>
            }
        </select>
        <span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
            @Localizer["AliasGenerationAgeRangeDescription"]
        </span>
    </div>
</div>

<div class="p-4  mx-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    <h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">@Localizer["ClipboardSettingsTitle"]</h3>

    <div class="mb-4">
        <label for="clipboardClearSeconds" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["ClipboardClearSecondsLabel"]</label>
        <select @bind="ClipboardClearSeconds" @bind:after="UpdateClipboardClearSeconds" id="clipboardClearSeconds" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
            <option value="0">@Localizer["ClipboardClearDisabledOption"]</option>
            <option value="5">@Localizer["ClipboardClear5SecondsOption"]</option>
            <option value="10">@Localizer["ClipboardClear10SecondsOption"]</option>
            <option value="15">@Localizer["ClipboardClear15SecondsOption"]</option>
        </select>
        <span class="block text-sm font-normal text-gray-500 dark:text-gray-400">
            @Localizer["ClipboardClearSecondsDescription"]
        </span>
        <div class="mt-2 p-3 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800">
            <p class="text-sm text-yellow-800 dark:text-yellow-200">
                @Localizer["ClipboardClearLimitationNote"]
            </p>
        </div>
    </div>
</div>

<div class="p-4  mx-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm dark:border-gray-700 sm:p-6 dark:bg-gray-800">
    <h3 class="mb-4 text-lg font-medium text-gray-900 dark:text-white">@Localizer["PasswordSettingsTitle"]</h3>

    <DefaultPasswordSettings />
</div>

@code {
    private IStringLocalizer Localizer => LocalizerFactory.Create("Pages.Main.Settings.General", "AliasVault.Client");

    private List<string> PrivateDomains => Config.PrivateEmailDomains
        .Where(d => !Config.HiddenPrivateEmailDomains.Contains(d))
        .ToList();
    private List<string> PublicDomains => Config.PublicEmailDomains;

    private string DefaultEmailDomain { get; set; } = string.Empty;
    private bool AutoEmailRefresh { get; set; }
    private string DefaultIdentityLanguage { get; set; } = string.Empty;
    private string DefaultIdentityGender { get; set; } = string.Empty;
    private string DefaultIdentityAgeRange { get; set; } = string.Empty;
    private string AppLanguage { get; set; } = string.Empty;
    private int ClipboardClearSeconds { get; set; }
    private List<LanguageOption> AvailableLanguages { get; set; } = new();
    private List<AgeRangeOption> AvailableAgeRanges { get; set; } = new();

    /// <inheritdoc />
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["BreadcrumbTitle"] });

        // Load available languages and age ranges from JavaScript utility
        AvailableLanguages = await JsInteropService.GetAvailableIdentityGeneratorLanguagesAsync();
        AvailableAgeRanges = await JsInteropService.GetAvailableIdentityGeneratorAgeRangesAsync();

        DefaultEmailDomain = DbService.Settings.DefaultEmailDomain;
        if (DefaultEmailDomain == string.Empty || Config.HiddenPrivateEmailDomains.Contains(DefaultEmailDomain))
        {
            if (HasValidPrivateDomains())
            {
                DefaultEmailDomain = PrivateDomains[0];
            }
            else if (PublicDomains.Count > 0)
            {
                DefaultEmailDomain = PublicDomains[0];
            }
        }
        AutoEmailRefresh = DbService.Settings.AutoEmailRefresh;

        await SetDefaultIdentityLanguageAsync();
        DefaultIdentityGender = DbService.Settings.DefaultIdentityGender;
        DefaultIdentityAgeRange = DbService.Settings.DefaultIdentityAgeRange;
        AppLanguage = DbService.Settings.AppLanguage;
        ClipboardClearSeconds = DbService.Settings.ClipboardClearSeconds;
    }

    /// <summary>
    /// Sets the default identity language.
    /// </summary>
    private async Task SetDefaultIdentityLanguageAsync()
    {
        var explicitLanguage = DbService.Settings.DefaultIdentityLanguage;
        if (!string.IsNullOrWhiteSpace(explicitLanguage))
        {
            // User has explicitly set a language, use it
            DefaultIdentityLanguage = explicitLanguage;
        }
        else
        {
            // No explicit language set, try to match UI language to identity generator language
            var mappedLanguage = await JsInteropService.MapUiLanguageToIdentityLanguageAsync(DbService.Settings.AppLanguage);
            DefaultIdentityLanguage = mappedLanguage ?? "en";
        }
    }

    /// <summary>
    /// Updates the default email domain.
    /// </summary>
    private async Task UpdateDefaultEmailDomain()
    {
        await DbService.Settings.SetDefaultEmailDomain(DefaultEmailDomain);
        StateHasChanged();
    }

    /// <summary>
    /// Updates the auto email refresh setting.
    /// </summary>
    private async Task UpdateAutoEmailRefresh()
    {
        await DbService.Settings.SetAutoEmailRefresh(AutoEmailRefresh);
        StateHasChanged();
    }

    /// <summary>
    /// Updates the default identity language setting.
    /// </summary>
    private async Task UpdateDefaultIdentityLanguage()
    {
        await DbService.Settings.SetDefaultIdentityLanguage(DefaultIdentityLanguage);
        StateHasChanged();
    }

    /// <summary>
    /// Updates the default identity gender setting.
    /// </summary>
    private async Task UpdateDefaultIdentityGender()
    {
        await DbService.Settings.SetDefaultIdentityGender(DefaultIdentityGender);
        StateHasChanged();
    }

    /// <summary>
    /// Updates the default identity age range setting.
    /// </summary>
    private async Task UpdateDefaultIdentityAgeRange()
    {
        await DbService.Settings.SetDefaultIdentityAgeRange(DefaultIdentityAgeRange);
        StateHasChanged();
    }

    /// <summary>
    /// Updates the app language setting.
    /// Also refreshes the identity generator language to reflect the new UI language if no explicit override is set.
    /// </summary>
    private async Task UpdateAppLanguage()
    {
        await LanguageService.SetLanguageAsync(AppLanguage);

        // After changing UI language, refresh identity generator language if user hasn't set an explicit override
        await SetDefaultIdentityLanguageAsync();
        StateHasChanged();
    }

    /// <summary>
    /// Updates the clipboard clear seconds setting.
    /// </summary>
    private async Task UpdateClipboardClearSeconds()
    {
        await DbService.Settings.SetClipboardClearSeconds(ClipboardClearSeconds);
        StateHasChanged();
    }

    /// <summary>
    /// Checks if the private domains are valid.
    /// </summary>
    private bool HasValidPrivateDomains()
    {
        if (PrivateDomains.Count == 0) {
            return false;
        }

        if (PrivateDomains.Count == 1)
        {
            var singleDomain = PrivateDomains[0];

            // If the domain is empty, return false.
            if (string.IsNullOrWhiteSpace(singleDomain))
            {
                return false;
            }

            // TODO: "DISABLED.TLD" was a placeholder used < 0.22.0 that has been replaced by an empty string.
            // That value is still here for legacy purposes, but it can be removed from the codebase in a future release.
            if (singleDomain == "DISABLED.TLD")
            {
                return false;
            }

            return true;
        }

        return true;
    }
}
